(function(){
	var Collections = require('Collections'),
	    ObjectUtils = require('ObjectUtils'),
	    StringUtils     = require('StringUtils'),
	    AutoCompleteResponse = require('AutoCompleteResponse').ctor;
	
	var Map        = Collections.Map,
	    iterate    = Collections.iterate,
	    formatEach = StringUtils.formatEach,
	    combine    = Collections.combine;
	
	var merge            = ObjectUtils.merge,
	    propertyAccessor = ObjectUtils.propertyAccessor;
	
	var format  = StringUtils.format;

	namespace('org.jsmud.entity');
	
	org.jsmud.entity.Room = function(roomService, data){
		this.__roomService = roomService;
		this.data = data;
		this.type = 'room';
	}
	org.jsmud.entity.Room.prototype = {
		commands : {
			create : {
				onExecute : function(title, description){
					if(!title) title = '[Title]';
					if(!description) description = 'Description';
					var data = {name:title, description:description};
					var room = new org.jsmud.entity.Room(this.__roomService, data);
					this.session.setRoom(room);
				},
				onAutoComplete : function(){
					
				}
			},
			save : {
				onExecute : function(){
					this.session.getRoom().save();
				}
			},
			get : {
				onExecute : function(item){
					var onResponse = this.onResponse;
					var room = this.owner;
					var user = this.session.getUser();
					
					var example = {$or:
						[{'container.collectionName':'user', 'container.position':'carryables', 'container._id':user.getId()}
						,{'container.collectionName':'user', 'container.position':'wearables', 'container._id':user.getId()}
						,{'container.collectionName':'room', 'container._id':room.getId()}
					]};
					var scope = this;
					this.session.itemService.findByExample(example, function(results){
						var _item;
						var ids = [];
						iterate(results, function(result){
							if( result.data.name == item ){
								_item = result;
							}
							ids.push(result.getId());
						});
						var retrieveItem = function(itemToShow){
							itemToShow.data.container.collectionName = 'user';
							itemToShow.data.container._id = user.getId();
							itemToShow.data.container.position = 'carryables';
							itemToShow.save(function(){
								user.refresh();
							});
						}
						console.log(results);
						if(!_item && ids.length){
							var example = {name:item, 'container.collectionName':'item', 'container._id':{'$in': ids}}
							scope.session.itemService.findByExample(example, function(itemsInContainer){
								if(itemsInContainer && itemsInContainer.length == 1){
									retrieveItem(itemsInContainer[0]);
								}else{
									console.log("Item not found in containers : " + item);
								}
							});
						}else if(_item){
							retrieveItem(_item);
						}else{
							console.log("Item not found in room : " + item);
						}
					});
				},
				onAutoComplete : function(value){
					var onResponse = this.onResponse;
					var room = this.owner;
					var example = {'container.collectionName':'room', 'container._id':room.getId()}
					this.session.itemService.findByExample(example, function(results){
						console.log(AutoCompleteResponse);
						onResponse(new AutoCompleteResponse(value, [{
							values:results
							, _toString:propertyAccessor('data.name')
							, toHTML : '${data.name}&nbsp;'
						}]));
					});
				}
			},			
			go : {
				onExecute : function(roomIdOrExit){
					var scope = this;
					var session = this.session;
					var room = session.getRoom();
					var roomService = room.__roomService;
					var commandService = this.commandService;
					var onResponse = this.onResponse;
					var roomId = this.owner.getExitId(roomIdOrExit);
					if(!roomId){
						onResponse('Room not found : ' + roomIdOrExit);
						return;
					}
					roomService.findById(roomId, function(newRoom){
						if(newRoom){
							session.setRoom(newRoom);
							commandService.execute('describe', onResponse);
						}else{
							onResponse('Room not found : ' + roomId);
						}
					});
				},
				onAutoComplete : function(value){
					var room = this.session.getRoom();
					var roomService = room.__roomService;
					var onResponse  = this.onResponse;
					roomService.list(function(results){
						var response = new AutoCompleteResponse(value, 
								[{
									values:room.data.exits
									, _toString:propertyAccessor('name')
									, toHTML : '<span>${name}</span>&nbsp;'
								}]);
						onResponse(response);
					});
				}
			},
			load : {
				onExecute : function(roomIdOrExit){
					var roomId = this.owner.getExitId(roomIdOrExit);
					if(!roomId) roomId = roomIdOrExit;
					
					var scope = this;
					var session = this.session;
					var room = session.getRoom();
					var roomService = room.__roomService;
					var commandService = this.commandService;
					var onResponse = this.onResponse;
					roomService.findById(roomId, function(newRoom){
						if(newRoom){
							session.setRoom(newRoom);
							commandService.execute('describe', onResponse);
						}else{
							onResponse('Room not found : ' + roomId);
						}
					});
				},
				onAutoComplete : function(value){
					var room = this.session.getRoom();
					var roomService = room.__roomService;
					var onResponse  = this.onResponse;
					roomService.list(function(results){
						var response = new AutoCompleteResponse(value, 
								[{
									values:results
									, _toString:propertyAccessor('data._id')
									, toHTML : '[<span>${data._id}</span>] ${data.name} &nbsp;'
								}, {
									values:room.data.exits
									, _toString:propertyAccessor('name')
									, toHTML : '[<span>${_id}</span>] ${name} &nbsp;'
								}]);
						onResponse(response);
					});
				}
			},
			createExit : {
				onExecute : function(dir, roomId){
					var session = this.session;
					var owner = this.owner;
					if( roomId ){
						this.owner.addExit(dir, roomId);
						this.owner.save(function(result){
							console.log(result);
						});
					}else{
						var data = {name:'Title', description:'Description'};
						var room = new org.jsmud.entity.Room(owner.__roomService, data);
						room.save(function(result){
							room.data._id = result.oids[0];
							owner.addExit(dir, room.getId());
							owner.save();
							session.setRoom(room);
						});
					}
				}
			}
		},
		getExits : function(){
			var map = {}
			var go  = this.commands.go;
			iterate(this.data.exits, function(exit){
				map[exit.name] = {
					onExecute : function(){
						go.onExecute.apply(this, [exit._id]);
					}
				}
			}, this);
			return map;
		},
		getCommands : function(onResponse){
			var map = {}
			Map.putAll(map, this.commands, merge({owner:this}).mapEntry);
			Map.putAll(map, this.getExits(), merge({owner:this}).mapEntry);
			onResponse(map);
		},
		save : function(onSave){
			this.__roomService.save(this.data, onSave);
		},
		getId : function(){
			return this.data._id;
		},
		getExitId : function(exitName){
			var result;
			iterate(this.data.exits, function(exit){
				if( exit.name == exitName ) result = exit._id;
				if( exit._id == exitName ) result = exit._id;
			})
			return result;
		},
		addExit : function(dir, roomId){
			if( !this.data.exits ) this.data.exits = [];
			this.data.exits.push({name:dir, _id:roomId})
		},
		getFormatString : function(){
			if( this.data.formatString ) return this.data.formatString;
			return '[${room.name}]<br/>${room.description}<br/><br/>';
		},
		refresh :function(){

		},
		describe : function() {
			var formatStr = '[${data.name}] <br/>'+
		          '${data.description} <br/>' +
		          '<br/>';
			if (this.items)
				formatStr += 'Items: ' + combine(formatEach(this.items, '<span>${data.name}</span>', ',&nbsp;', 'None')) + '<br/>';
			if (this.data.exits)
				formatStr += 'Obvious exits : ' + combine(formatEach(this.data.exits, '<span>${name}</span>', ',&nbsp;'));
			else
				formatStr += 'Obvious exits : None';
			return format(formatStr, this);
		}
	}
})()